package cn.tangsihai.hrm.service.impl;

import cn.tangsihai.hrm.doc.CourseESDoc;
import cn.tangsihai.hrm.dto.CourseDto;
import cn.tangsihai.hrm.mapper.HighlightResultMapper;
import cn.tangsihai.hrm.repository.CourseElasticsearchRepository;
import cn.tangsihai.hrm.service.IESService;
import cn.tangsihai.hrm.util.PageList;
import cn.tangsihai.hrm.vo.AggPageList;
import cn.tangsihai.hrm.vo.TermsAggBucket;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class ESServiceImpl implements IESService {
    @Autowired
    private CourseElasticsearchRepository courseElasticsearchRepository;
    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;
    @Autowired
    private HighlightResultMapper highlightResultMapper;
    /**
     * 从es中按照检索条件检索：
     *      1.构建查询条件
     *      2.排序
     *      3.分页
     *      4.条件
     * @param dto
     * @return
     */
    @Override
    public PageList<CourseESDoc> searchCourse(CourseDto dto) {
        // 1.构建查询条件
        NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();

        // 2.排序
        // 2.1排序字段
        String sortField = "onlineTime";
        if (StringUtils.isNotEmpty(dto.getSortField())){
            switch (sortField){
                case "xl": sortField = "saleCount"; break;
                case "xp": sortField = "onlineTime"; break;
                case "pl": sortField = "commentCount"; break;
                case "jg": sortField = "price"; break;
                case "rq": sortField = "viewCount"; break;
            }
            // 2.2排序方式
            SortOrder desc = SortOrder.ASC;
            if (StringUtils.isNotEmpty(dto.getSortType()) && dto.getSortType().equalsIgnoreCase("desc")){
                desc =SortOrder.DESC;
            }
            searchQueryBuilder.withSort(SortBuilders.fieldSort(sortField).order(desc));
        }

        // 3.分页
        PageRequest pageRequest = PageRequest.of(dto.getPage() - 1, dto.getRows());
        searchQueryBuilder.withPageable(pageRequest);

        // 4.条件
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        // 4.1 must--必须包含的条件
        if (StringUtils.isNotEmpty(dto.getKeyword())){
            boolQuery.must(QueryBuilders.wildcardQuery("name", dto.getKeyword() + "*"));
        }
        // 4.3 过滤
        // 课程类型id
        if (dto.getCourseTypeId() != null){
            boolQuery.filter(QueryBuilders.termQuery("courseTypeId", dto.getCourseTypeId()));
        }
        // 等级
        if (StringUtils.isNotEmpty(dto.getGradeName())){
            boolQuery.filter(QueryBuilders.termQuery("gradeName", dto.getGradeName()));
        }
        // 机构名字
        if (StringUtils.isNotEmpty(dto.getTenantName())){
            boolQuery.filter(QueryBuilders.termQuery("tenantName", dto.getTenantName()));
        }
        // 价格
        if (dto.getPriceMin() != null || dto.getPriceMax() != null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(dto.getPriceMin()).lte(dto.getPriceMax()));
        }
        // **在查询语句中加入查询条件
        searchQueryBuilder.withQuery(boolQuery);

        // 5.关键字高亮
        HighlightBuilder.Field field = new HighlightBuilder.Field("name")
                .preTags("<span style='color:red'>")
                .postTags("</span>");
        // 5.1 将高亮设置加入查询构造器中
        searchQueryBuilder.withHighlightFields(field);

        // 6.添加聚合条件：等级、机构聚合
        TermsAggregationBuilder gradeNameAgg = AggregationBuilders.terms("gradeNameAgg").field("gradeName");
        TermsAggregationBuilder tenantNameAgg = AggregationBuilders.terms("tenantNameAgg").field("tenantName");
        searchQueryBuilder.addAggregation(gradeNameAgg).addAggregation(tenantNameAgg);

        // .索引存储库调用查询方法查询数据 Page<CourseESDoc> search =
//        Page<CourseESDoc> search = courseElasticsearchRepository.search(searchQueryBuilder.build());
        AggregatedPage<CourseESDoc> search = elasticsearchTemplate.queryForPage(searchQueryBuilder.build(), CourseESDoc.class, highlightResultMapper);
        // 存放聚和结果
        Map<String,List<TermsAggBucket>> termsAggResult = new HashMap<>();
        // 将结果进行聚和，存入map中
        Map<String, Aggregation> aggregationMap = search.getAggregations().asMap();
        aggregationMap.keySet().forEach(key->{ // 遍历map方式：将key转化为set遍历
            // Bucke列表
            List<TermsAggBucket> termsAggBuckets = new ArrayList<>();
            // key : 聚合的名字
            // 值aggregation ：
            StringTerms aggregation = (StringTerms) aggregationMap.get(key);
            aggregation.getBuckets().forEach(bucket -> {
                // 每一个bucket ,//名字
                String name = bucket.getKey().toString();
                // 数量
                long docCount = bucket.getDocCount();
                // 一个 Bucket转成一个 TermsAggBucket对象
                termsAggBuckets.add(new TermsAggBucket(name , docCount));
            });
            // 加入到聚合结果
            termsAggResult.put(key,termsAggBuckets );
        });

        return new AggPageList(search.getTotalElements() , search.getContent(),termsAggResult);

    }
}
